package com.bysc.commentservice.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bysc.baseservice.handler.BaiYunException;
import com.bysc.commentservice.client.UserClient;
import com.bysc.commentservice.entity.CommentSon;
import com.bysc.commentservice.entity.vo.CommentFormVo;
import com.bysc.commentservice.entity.vo.CommentQueryVo;
import com.bysc.commentservice.entity.vo.SonCommentFormVo;
import com.bysc.commentservice.mapper.CommentSonMapper;
import com.bysc.commentservice.service.CommentSonService;
import com.bysc.commonutils.ResultCode;
import com.bysc.commonutils.constant.MessageConstant;
import com.bysc.commonutils.utils.DateUtil;
import com.bysc.commonutils.vo.PageResult;
import com.bysc.commonutils.vo.UserInfoVo;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.regex.Pattern;

import static com.bysc.commonutils.constant.RedisConstant.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author kkk
 * @since 2024-06-15
 */
@Slf4j
@Service
public class CommentSonServiceImpl extends ServiceImpl<CommentSonMapper, CommentSon> implements CommentSonService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private UserClient userClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;


    @Override
    public void updateSonCommentById(CommentFormVo sonCommentFormVo, Object id) {
        // 判空
        if (ObjectUtils.isEmpty(id)) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATECOMMENT_ERROR);
        }
        String postId = sonCommentFormVo.getPostId();
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        CommentSon commentSost = mongoTemplate.findOne(query, CommentSon.class);
        if (commentSost == null) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATECOMMENT_ERROR);
        }
        Update update = new Update();
        update.set("contentImage", sonCommentFormVo.getContentImage());
        update.set("content", sonCommentFormVo.getContent());
        update.set("gmtModified", new Date());
        UpdateResult result = null;
        try {
            result = mongoTemplate.updateFirst(query, update, CommentSon.class);
        } catch (Exception e) {
            throw new BaiYunException(ResultCode.ERROR, e.getMessage());
        }
        log.info("更新子评论,详细信息：{}", result);
    }

    @Override
    public CommentSon deleteSonCommentById(Object id) {
// 判空
        if (id == null) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.VALIDATECOMMENT_ERROR);
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        CommentSon commentSon = mongoTemplate.findOne(query, CommentSon.class);
        if (commentSon==null) {
            throw new BaiYunException(ResultCode.ERROR, MessageConstant.INFO_ERROR);
        }
        Update update = new Update();
        update.set("isDeleted", true);
        UpdateResult remove = null;
        try {
            remove = mongoTemplate.updateFirst(query, update, CommentSon.class);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaiYunException(ResultCode.ERROR, e.getMessage());
        }
        log.info("删除子评论,详细信息：{}", remove);
        return commentSon;
    }

    @Override
    public CommentSon addSonCommentByCommentFormVoAndToken(SonCommentFormVo sonCommentFormVo, String userId) {
        CommentSon commentSon = new CommentSon();
        BeanUtils.copyProperties(sonCommentFormVo, commentSon);
        commentSon.setUserId(userId);
        commentSon.setIsDeleted(false);
        commentSon.setGmtCreate(new Date());
        commentSon.setGmtModified(new Date());
        CommentSon insert = mongoTemplate.insert(commentSon);
        return insert;
    }

    @Override
    public PageResult getSonCommentListByTokenAndPpCommentIdOrderByCreatTime(String userId, Object id, Integer page, Integer limit) {
        // 按照最新发布时间降序排序
        Sort sort = Sort.by(Sort.Direction.DESC, "gmtCreate");
        Query query = new Query();
        query.addCriteria(Criteria.where("ppCommentId").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        //获取总数
        long total = mongoTemplate.count(query, CommentSon.class);
        // 分页
        Pageable pageable = PageRequest.of(page - 1, limit, sort);
        query.with(pageable);
        List<CommentSon> commentSonList = mongoTemplate.find(query, CommentSon.class);
        String setKey = COMMENT_SONCOMMENT_USER_LIKE + userId;
        for (CommentSon commentSon : commentSonList) {
            String hashKey = COMMENT_SONCOMMENT + commentSon.getId();
            getInfo(commentSon, setKey, hashKey);
        }
        PageResult pageResult = new PageResult(total, commentSonList.size(), commentSonList, page);
        return pageResult;
    }

    @Override
    public PageResult getSonCommentListByTokenAndPpCommentIdOrderBylike(String userId, Object id, Integer page, Integer limit) {
        // 按照最新发布时间降序排序
        Query query = new Query();
        query.addCriteria(Criteria.where("ppCommentId").is(id));
        query.addCriteria(Criteria.where("isDeleted").is(false));
        List<CommentSon> allCommentSons = mongoTemplate.find(query, CommentSon.class);

        // 从Redis中获取点赞数并设置到CommentParent对象中
        for (CommentSon commentSon : allCommentSons) {
            String hashKey = COMMENT_SONCOMMENT + commentSon.getId();
            Integer likes = (Integer) redisTemplate.opsForHash().get(hashKey, _LIKE);
            commentSon.setLikes(likes);
        }
        // 按照点赞数降序排序
        allCommentSons.sort((o1, o2) -> {
            int likesComparison = o2.getLikes().compareTo(o1.getLikes()); // 降序排序
            if (likesComparison == 0) {
                // 如果点赞数相同，则比较创建时间
                return o1.getGmtCreate().compareTo(o2.getGmtCreate()); // 升序排序
            }
            return likesComparison;
        });
        // 计算分页的起始和结束索引
        int start = (page - 1) * limit;
        int end = Math.min(start + limit, allCommentSons.size());
        // 创建分页结果
        List<CommentSon> pageCommentSons = allCommentSons.subList(start, end);
        // 获取相关详细信息

        String setKey = COMMENT_SONCOMMENT_USER_LIKE + userId;
        for (CommentSon commentSon : pageCommentSons) {
            String hashKey = COMMENT_SONCOMMENT + commentSon.getId();
            getInfo(commentSon, setKey, hashKey);
        }
        PageResult pageResult = new PageResult((long) allCommentSons.size(), pageCommentSons.size(), pageCommentSons, page);
        return pageResult;
    }

    @Override
    public PageResult getAllSonCommentListByQueryVoOrderByCreatTime(Integer page, Integer limit, CommentQueryVo queryVo) {
        String value = queryVo.getValue();
        String userId = queryVo.getUserId();
        String start = queryVo.getStart();
        String end = queryVo.getEnd();

        Query query = new Query();
        if (!StringUtils.isEmpty(userId)) {
            query.addCriteria(Criteria.where("userId").is(userId));
        }
        query.addCriteria(Criteria.where("isDeleted").is(false));
        if (!StringUtils.isEmpty(start) && StringUtils.isEmpty(end)) { // 只有start
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start)));
        } else if (StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 只有end
            query.addCriteria(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end)));
        } else if (!StringUtils.isEmpty(start) && !StringUtils.isEmpty(end)) { // 有start有end
            query.addCriteria(Criteria.where("gmtCreate").gte(DateUtil.dateToISODate(start))
                    .andOperator(Criteria.where("gmtCreate").lte(DateUtil.dateToISODate(end))));
        }
        if (!StringUtils.isEmpty(value)) {
            Pattern pattern = Pattern.compile("^.*" + value + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("content").regex(pattern));
        }
        //获取总数
        long total = mongoTemplate.count(query, CommentSon.class);

        // 分页
        // 按照最新发布时间降序排序
        Sort sort = Sort.by(Sort.Direction.DESC, "gmtCreate");
        Pageable pageable = PageRequest.of(page - 1, limit, sort);
        query.with(pageable);
        List<CommentSon> commentSons = mongoTemplate.find(query, CommentSon.class);
        //获取评论详细信息
        String setKey = "";
        for (CommentSon commentSon : commentSons) {
            String hashKey = COMMENT_SONCOMMENT + commentSon.getId();
            getInfo(commentSon, setKey, hashKey);
        }
        PageResult pageResult = new PageResult(total, commentSons.size(), commentSons, page);
        //TODO 此处缓存pageResult
        return pageResult;
    }

    /**
     * 获取评论相关信息，如点赞量，是否点赞过，用户信息等
     *
     * @param commentSon 子评论
     * @param setKey     点赞集合键
     * @param hashKey    哈希键
     */
    private void getInfo(CommentSon commentSon, String setKey, String hashKey) {
        String sonUserId = commentSon.getUserId();
        String parentUserId = commentSon.getParentUserId();
        String commentSonId = commentSon.getId();

        // 异步获取子评论用户信息
        CompletableFuture<UserInfoVo> userFuture = CompletableFuture.supplyAsync(() -> {
            try {
                UserInfoVo user = JSON.parseObject(JSON.toJSONString(userClient.getUserInfoById(sonUserId).getData().get("user")), UserInfoVo.class);
                if (user == null) {
                    throw new BaiYunException(ResultCode.ERROR, "获取用户信息失败");
                }
                return user;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, threadPoolExecutor);

        // 异步获取父评论用户信息
        CompletableFuture<UserInfoVo> parentUserFuture = CompletableFuture.supplyAsync(() -> {
            if (StringUtils.isEmpty(commentSon.getPpCommentId()) || commentSon.getPpCommentId().equals(commentSon.getParentCommentId())) {
                return null;
            }
            try {
                UserInfoVo parentUser = JSON.parseObject(JSON.toJSONString(userClient.getUserInfoById(parentUserId).getData().get("user")), UserInfoVo.class);
                return parentUser;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }, threadPoolExecutor);

        // 异步获取评论点赞数量
        CompletableFuture<Integer> likeCountFuture = CompletableFuture.supplyAsync(() -> {
            return (Integer) redisTemplate.opsForHash().get(hashKey, _LIKE);
        }, threadPoolExecutor);

        // 异步判断用户是否点赞过
        CompletableFuture<Boolean> isLikedFuture = CompletableFuture.supplyAsync(() -> {
            if (StringUtils.isEmpty(setKey)) {
                return false;
            }
            return redisTemplate.opsForSet().isMember(setKey, commentSonId);
        }, threadPoolExecutor);

        CompletableFuture.allOf(userFuture, parentUserFuture, likeCountFuture, isLikedFuture).join();

        try {
            UserInfoVo user = userFuture.get();
            commentSon.setUserAvatar(user.getAvatar());
            commentSon.setUserUseTitle(user.getTitles());
            commentSon.setUserName(user.getNickname());
            commentSon.setIsJoin(user.getIsJoin());

            UserInfoVo parentUser = parentUserFuture.get();
            if (parentUser != null) {
                commentSon.setParentUserName(parentUser.getNickname());
            }

            commentSon.setLikes(likeCountFuture.get());
            commentSon.setIsLiked(isLikedFuture.get());
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

}
